package net

/*
*创建tcp或者websocket服务
 */
import (
	"errors"
	"fmt"
	"gamesdk/common/log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

type Model int

//网络模式
const (
	//tcp模式
	TCP_MODEL = iota
	//websocket模式
	WEB_SOCKET_MODEL
)

/*
*定义一个服务接口对象
 */
type NetInter interface {
	//初始化逻辑
	InitLogic(logic *Manager) LogicInter
	Error(error)
}

/*
*tcp服务
 */
type Net struct {
	ip        string         //监听的IP地址
	port      int            //监听的端口号
	count     int32          //在线的链接数
	pid       int            //进程pid
	waitGroup sync.WaitGroup //协程序数量
	server    NetInter       //服务接口
	status    bool           //服务状态
	heartbeat int            //心跳时间
	upgrader  websocket.Upgrader
	managers  sync.Map
}

/*
*创建一个网络服务
 */
func NewNet(ip string, port int, heartbeat int, server NetInter) *Net {
	i := net.ParseIP(ip)
	if i == nil {
		server.Error(errors.New("ip error"))
	}
	if port <= 0 {
		server.Error(errors.New("port error"))
	}
	srv := &Net{
		ip:        ip,
		port:      port,
		pid:       0,
		status:    false,
		server:    server,
		upgrader:  websocket.Upgrader{},
		count:     0,
		heartbeat: heartbeat,
	}
	return srv
}

/*
*启动一个网络服务
 */
func (this *Net) Run(model Model) {
	this.pid = os.Getpid()
	c := make(chan os.Signal)
	//监听指定信号
	signal.Notify(c, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT)
	//TCP模式
	if model == TCP_MODEL {
		this.status = true
		go this.RunTcp()
	}
	//websocket模式
	if model == WEB_SOCKET_MODEL {
		this.status = true
		go this.RunWebSocket()
	}
	msg := <-c
	this.status = false
	this.managers.Range(func(k, v interface{}) bool {
		v.(*Manager).Exit()
		return true
	})
	this.waitGroup.Wait()
	log.Info("exit msg %v", msg)
}

/*
*启动tcp服务
 */
func (this *Net) RunTcp() {
	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.ip, this.port))
	if err != nil {
		this.server.Error(err)
		return
	}
	defer l.Close()
	log.Info("TCP IS RUN %s", fmt.Sprintf("%s:%d", this.ip, this.port))
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Error(err.Error())
			return
		}
		go this.funcTcpConnect(conn)
	}
}

func (this *Net) RunWebSocket() {
	this.upgrader = websocket.Upgrader{
		// 解决跨域问题
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	gin.SetMode(gin.ReleaseMode)
	router := gin.Default()
	router.GET("/", this.funcWebSocketConnect)
	log.Info("WEBSOCKET IS RUN %s", fmt.Sprintf("%s:%d", this.ip, this.port))
	err := router.Run(fmt.Sprintf("%s:%d", this.ip, this.port))
	if err != nil {
		this.server.Error(err)
		return
	}
}

/*
*建立websokcet链接
 */
func (this *Net) funcWebSocketConnect(c *gin.Context) {
	r := c.Request
	w := c.Writer
	r.Header.Del("Origin")
	this.waitGroup.Add(1)
	defer this.waitGroup.Done()
	conn, err := this.upgrader.Upgrade(w, r, nil)
	if err != nil {
		return
	}
	atomic.AddInt32(&this.count, 1)
	manager := NewWebManager(this, conn, conn.RemoteAddr().String(), this.heartbeat)
	this.managers.Store(manager.GetIp(), manager)
	logic := this.server.InitLogic(manager)
	manager.BindLogic(logic)
	manager.Start()
	this.managers.Delete(manager.GetIp())
	conn.Close()
	atomic.AddInt32(&this.count, -1)
	return
}

/*
*建立tcp链接
 */
func (this *Net) funcTcpConnect(conn net.Conn) {
	this.waitGroup.Add(1)
	defer this.waitGroup.Done()
	atomic.AddInt32(&this.count, 1)
	manager := NewTcpManager(this, conn, conn.RemoteAddr().String(), this.heartbeat)
	this.managers.Store(manager.GetIp(), manager)
	logic := this.server.InitLogic(manager)
	manager.BindLogic(logic)
	manager.Start()
	this.managers.Delete(manager.GetIp())
	conn.Close()
	atomic.AddInt32(&this.count, -1)
	return
}

/*
*获取服务的PID
 */
func (this *Net) GetPid() int {
	return this.pid
}

/*
*获取服务连接数量
 */
func (this *Net) GetCount() int32 {
	return this.count
}
